#ifndef ack_queue_h
#define ack_queue_h

#include "packet.h"
#include "cope-packet.h"
#include "mobilenode.h"
#include <list>
#include <bitset>
using std::list;
using std::bitset;

#define ACKMAP_TOTAL_SIZE     256
#define ACKMAP_SIZE           8

class Packet;
typedef struct {
    u_int16_t local_seqnum; // local sequence number of Non-Acked pkt
    u_int8_t rcounter; // counter for times of retransmission
    Packet* ppkt; // pointer to packet
  // Packet** ppkt_addr;
} non_ack_entry_t;

typedef struct {
    int nodeid; // next hop
    list<non_ack_entry_t>* entries;
} non_ack_t;

typedef struct {
    int neighbor; //MAC address of the neighbor
    u_int16_t lastack; // last ack sequence number
    u_int16_t shifts; // number of bits shifted
    //    u_int8_t rtimes; // number of retransmission times
    bitset<ACKMAP_TOTAL_SIZE> ackmap;
} ack_pend_t;

typedef list<non_ack_entry_t>::iterator entry_iter_t;
typedef list<non_ack_t>::iterator non_iter_t;
typedef list<ack_pend_t>::iterator pend_iter_t;

class COPE;
class NonAckQueue {
 public:
    NonAckQueue();
    ~NonAckQueue();
    
    
    entry_iter_t lookup_entry(non_iter_t it_non, u_int16_t local_seqnum);
    non_iter_t lookup_node(int nodeid);
    bool has_node(int nodeid);
    u_int8_t enqueue(int nodeid, u_int16_t local_seqnum, Packet* p);
    u_int8_t get_packet(int nodeid, u_int16_t local_seqnum, Packet** p);
    u_int8_t lookup_packet(int nodeid, u_int16_t local, Packet** p);    
    u_int16_t get_local_seq(int nodeid, int pktid);
    
    void delete_entry(int nodeid, u_int16_t local_seqnum);
    void showNonAck();
   
 private:
    list<non_ack_t>* non_ack_list_;

    void delete_node(int nodeid);

    void enqueue_node(int nodeid, u_int16_t local_seqnum, Packet* p);
    void enqueue_entry(int nodeid, u_int16_t local_seqnum, Packet* p,
		       non_iter_t it_non);
    
};


class AckPendQueue {
 public:
    AckPendQueue();
    ~AckPendQueue();
    
    pend_iter_t lookup_pend(int neighbor);
    bool has_pend(int neighbor);
    void delete_pend(int neighbor);
    void enqueue_pend(int neighbor, u_int16_t local_seqnum, bool set, COPE* cope);
    void update_pend(int neighbor, u_int16_t local_seqnum);
    hdr_ack_t* get_pend(int neighbor, COPE* cope);

    /*
     *Shift Function Requirement:
     *1. I will pass a hdr_ack_list as parameter
     *2. iterate each item in ack list, shift 8 bits left according to item's neighbor entry 
     *
     *The function is called in extract_acks in COPE, by the form of 
     * 
     *pend_acks_->shift(HDR_COPE(pkt)->hdr_ack_list_);
     */

    list<ack_pend_t>* ack_pend_list_;

 private:
    u_int16_t shift_num_;
};

#endif
